/*
 *  Copyright 2008-2010 the original author or authors.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.openaecfm.spf.io;

import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.openaecfm.spf.model.EntityInstance;
import org.openaecfm.spf.model.FileDescription;
import org.openaecfm.spf.model.FileName;
import org.openaecfm.spf.model.FileSchema;
import org.openaecfm.spf.model.HeaderEntity;
import org.openaecfm.spf.model.SimpleEntityInstance;
import org.openaecfm.spf.parser.ParseException;
import org.openaecfm.spf.parser.SPFReader;

/**
 * @author Qiu Kuining
 */
public class DefaultImportSessionImpl extends AbstractSPFReadAwareImpl
		implements IImportSession, ISPFReadAware {

	private IAppDataManager appDataManager = new SimpleAppDataManagerImpl();
	private IEntityInstanceInputFactory factory;
	private IEntityInstanceInputFactoryUtil factoryUtil;
	private FileDescription fileDescription;
	private FileName fileName;
	private FileSchema fileSchema;

	// private Map<String, Object> pojo_map = new HashMap<String, Object>();
	private InputStream is;

	private SPFReader reader;
	private Set<EntityInstance> unfinished_work = new HashSet<EntityInstance>();

	public DefaultImportSessionImpl(InputStream is,
			IEntityInstanceInputFactoryUtil factoryUtil) {
		this.is = is;
		reader = new SPFReader(is);
		reader.setReadAware(this);
		this.factoryUtil = factoryUtil;
	}

	@Override
	public void begin() {
		try {
			reader.syntax();
		} catch (ParseException e) {
			logger.error("Parse exception" + e.toString());
		}
	}

	@Override
	public void close() {
		try {
			appDataManager = null;
			unfinished_work.clear();
			is.close();
		} catch (Exception ex) {
			Logger.getLogger(DefaultImportSessionImpl.class.getName()).log(
					Level.SEVERE, null, ex);
		}
	}

	@SuppressWarnings("rawtypes")
	@Override
	public void endOfEntityInstance(EntityInstance ei) {
		SimpleEntityInstance sei = (SimpleEntityInstance) ei;
		IEntityInstanceInput input = factory.createEntityInstanceInput(sei
				.getSimpleRecord().getKeyword());

		input.importSPF(ei, appDataManager);
		if (!input.isFinished())
			unfinished_work.add(ei);
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void endOfExchangeFile() {
		for(EntityInstance ei : unfinished_work){
			SimpleEntityInstance sei = (SimpleEntityInstance) ei;
			IEntityInstanceInput input = factory.createEntityInstanceInput(sei
					.getSimpleRecord().getKeyword());
			try {
				Object pojo = appDataManager.getObject(ei.getName());
				input.resolveReferenceParameter(ei, pojo, appDataManager);
			} catch (NotFoundException e) {
				logger.error(sei.getName() + " references a not found entity " + e.getMessage());
			}
		}

		logger.info("End of Part 21 file");
	}

	@Override
	public void endOfHeaderEntity(HeaderEntity he) {
		String he_keyword = he.getKeyword();

		if (he_keyword.equals("FILE_DESCRIPTION")) {
			// Set file description
			fileDescription = new FileDescriptionIO().importSPF(he);
		} else if (he_keyword.equals("FILE_NAME")) {
			// Set file name
			fileName = new FileNameIO().importSPF(he);
		} else if (he_keyword.equals("FILE_SCHEMA")) {
			// Set file schema
			fileSchema = new FileSchemaIO().importSPF(he);
		} else {
			return;
		}
	}

	@Override
	public void endOfHeaderSection() {
		String schemaName = getFileSchema().getSchemaName();
		setFactory(factoryUtil.createFactory(schemaName));

		logger.info("End of Header Section");
	}

	@Override
	public FileDescription getFileDescription() {
		return fileDescription;
	}

	@Override
	public FileName getFileName() {
		return fileName;
	}

	@Override
	public FileSchema getFileSchema() {
		return fileSchema;
	}

	public int getReferenceEntityNumber() {
		return this.unfinished_work.size();
	}

	@Override
	public void setAppDataManager(IAppDataManager appDataManager) {
		this.appDataManager = appDataManager;
	}

	public void setFactory(IEntityInstanceInputFactory factory) {
		this.factory = factory;
	}

	public void setFactoryUtil(IEntityInstanceInputFactoryUtil factoryUtil) {
		this.factoryUtil = factoryUtil;
	}
}
